package furnitures 
{
	import adobe.utils.CustomActions;
	import alternativa.engine3d.core.Object3DContainer;
	import alternativa.engine3d.core.Sorting;
	import alternativa.engine3d.materials.FillMaterial;
	import alternativa.engine3d.objects.Mesh;
	import alternativa.engine3d.primitives.Box;
	import alternativa.engine3d.primitives.Plane;
	import app.AppSettings;
	import debug.DebugView;
	import drawing.ColorPalette;
	import drawing.IPalette;
	import flash.geom.Point;
	import utils.ArrayUtil;
	import utils.Logger;
	/**
	 * ...
	 * @author Dmitriy Gaiduk
	 */
	public class FurnitureAlter extends Object3DContainer
	{
		private var _furnMesh:FurnitureMesh;
		private var _scale:Number;
		
		private static const FOOT_WIDTH:Number = 50 * AppSettings.SCALE_FACTOR;
		private static const FOOT_HEIGHT_SCALED:Number = 100 * AppSettings.SCALE_FACTOR;
		private static const DECOR_FRONT_SPACING:Number = 15;
		
		public var positionY:Number = 0;
		private var _model:FurnitureModel;
		private var _tabletopMesh:FurnitureMesh;
		private var _decorMesh:FurnitureMesh;
		private var _debugV:DebugView;
		private var _furnName:String;
		
		private var _shelvesMeshes:Vector.<FurnitureMesh>;
		
		public function FurnitureAlter(model:FurnitureModel, scaleFactor:Number, 
										debugV:DebugView = null ,nm:String = "") 
		{
			_scale = scaleFactor;
			log("scale: " + _scale);
			_model = model;
			_debugV = debugV;
			_furnName = nm;
			initFurnniture();
		}
		
		private function initFurnniture():void 
		
		{	
		
			var buildTop:Boolean = !_model.hasTabletop;
			var buildBottom:Boolean = true;
			
			if (_model.extra != FurnitureModel.EXTRA_NO_FACE && !_model.forceShelves) {
				_model.shelves = null;
			}
			
			if (_model.shelves != null && _model.shelves.length > 0) {
				buildTop = false;
				buildBottom = false;
				_model.doubleSided = true;
			}
			
			if (_model.forceShelves) {
				buildTop = true;
				buildBottom = true;
				_model.doubleSided = true;
			}
			
			_furnMesh = new FurnitureMesh(_model, _scale, buildTop, buildBottom, _furnName, _debugV);
			_furnMesh.sorting = Sorting.DYNAMIC_BSP;
			positionY = _furnMesh.positionY;
			addChild(_furnMesh);
			if(_furnMesh.model.foots!=null && _furnMesh.model.foots.positions!=null){
				_furnMesh.z = FOOT_HEIGHT_SCALED;
				addFoots();
			}
			
			if (_model.hasTabletop){
				buildTableTop();
			}
			
			// add shelves
			buildShelves();
		}
		
		private function buildTableTop():void {
			var tabletopH:Number = 50;
			var buildBottom:Boolean = false;
			if (_model.shelves != null && _model.shelves.length > 0) {
				buildBottom = true;
			}
			var tabletopModel:FurnitureModel = _model.clone();
			tabletopModel.doubleSided = false;
			tabletopModel.furnitureHeight = tabletopH;
			_tabletopMesh = new FurnitureMesh(tabletopModel, _scale, true, buildBottom);
			_tabletopMesh.z = _furnMesh.furnitureHeight + FOOT_HEIGHT_SCALED;
			_tabletopMesh.sorting = Sorting.DYNAMIC_BSP;
			addChild(_tabletopMesh);
			
			// set faces type
			var sideInfo:SideInfo;
			for (var i:int = 0; i < _tabletopMesh.faces.length; i++) {
				sideInfo = _tabletopMesh.faces[i].id as SideInfo;
				
				if (sideInfo == null) {
					continue;
				}
				
				sideInfo.type = SideInfo.TABLETOP_FACE;
			}
			
		}
		
		private function addFoots():void
		{
			
			if (_furnMesh.model.foots == null) {
				return;
			}
			
			var points:Array = [];
			
			for each(var p:Point in _furnMesh.model.foots.positions)
			{
				points.push([p.x, p.y]);
			}
			
			points = makeEdgeSideAlign(points);
			
			for (var i:int = 0; i < points.length; i++ )
			{
				 _furnMesh.model.foots.positions[i].x = points[i][0];
				 _furnMesh.model.foots.positions[i].y = points[i][1];
			}
			
			var fillMat:FillMaterial = new FillMaterial(0x004080, 1, 1, 0x000000);
			for each(p in  _furnMesh.model.foots.positions)
			{
				var foot3D:Box = new Box(FOOT_WIDTH, FOOT_WIDTH, FOOT_HEIGHT_SCALED);
				foot3D.sorting = Sorting.DYNAMIC_BSP;
				foot3D.setMaterialToAllFaces(fillMat);
				addChild(foot3D);
				foot3D.x = p.x;
				foot3D.y = p.y;
				foot3D.z = FOOT_HEIGHT_SCALED*0.5;
			}
			
			// add decor	
			buildDecor();
			
		
		}
		
		private function buildShelves():void 
		{
			if (_model.shelves == null || _model.shelves.length == 0) {
				return;
			}
			
			_shelvesMeshes = new Vector.<FurnitureMesh>();
			
			// mm
			var shelfH:Number = 20;
			var shelfModelMain:FurnitureModel = _model.clone();
			shelfModelMain.furnitureHeight = shelfH;
			shelfModelMain.doubleSided = false;
			
			//prevent z-fighting, mm
			var shelfSpacing:Number = 5;
			
			var scaleArray:Number = (_model.furnitureWidth - shelfSpacing * 2) / _model.furnitureWidth;
			var scaleByDepth:Number = ((_model.furnitureDepth - shelfSpacing) / _model.furnitureDepth);
			
			if(shelfModelMain.shapePoints !=null){
				ArrayUtil.scaleArrays(shelfModelMain.shapePoints, scaleArray);
			}
			
			shelfModelMain.furnitureWidth *= scaleArray;
			shelfModelMain.furnitureDepth *= scaleByDepth;
			
			var shelfeMesh:FurnitureMesh;
			var shelfModel:FurnitureModel;
			var sideInfo:SideInfo;
			var j:int;
			var shiftZ:Number = 0;
			if (_model.foots != null) {
				shiftZ = FOOT_HEIGHT_SCALED;
			}
			for (var i:int = 0; i < _model.shelves.length; i++ ) {
				shelfModel = shelfModelMain.clone();
				shelfModel.doubleSided = false;
				shelfeMesh = new FurnitureMesh(shelfModel, _scale, true, true);
				shelfeMesh.z = _furnMesh.furnitureHeight -  _furnMesh.furnitureHeight * _model.shelves[i]
									+ shiftZ - shelfH * _scale;
				shelfeMesh.x = shelfSpacing * _scale;
				shelfeMesh.sorting = Sorting.DYNAMIC_BSP;
				addChild(shelfeMesh);
				
				_shelvesMeshes.push(shelfeMesh);
				
				for (j = 0; j < shelfeMesh.faces.length; j++) {
					sideInfo = shelfeMesh.faces[j].id as SideInfo;
					
					if (sideInfo == null) {
						continue;
					}
					
					sideInfo.type = SideInfo.CORPUS_FACE;
				}
			}
			
			if (_model.forceShelves) {
				return;
			}
			// top
			if(!_model.hasTabletop){
				shelfModel = _model.clone();
				shelfModel.doubleSided = false;
				shelfModel.furnitureHeight = shelfH;
				shelfeMesh = new FurnitureMesh(shelfModel, _scale, true, true);
				shelfeMesh.z = _furnMesh.furnitureHeight + shiftZ - shelfH * _scale;
				//shelfeMesh.x = shelfSpacing * _scale;
				shelfeMesh.sorting = Sorting.DYNAMIC_BSP;
				addChild(shelfeMesh);
				_shelvesMeshes.push(shelfeMesh);
				
				for (j = 0; j < shelfeMesh.faces.length; j++) {
					sideInfo = shelfeMesh.faces[j].id as SideInfo;
					
					if (sideInfo == null) {
						continue;
					}
					
					sideInfo.type = SideInfo.CORPUS_FACE;
				}
			}
			
			//bottom
			shelfModel = _model.clone();
			shelfModel.doubleSided = false;
			shelfModel.furnitureHeight = shelfH;
			shelfeMesh = new FurnitureMesh(shelfModel, _scale, true, true);
			shelfeMesh.z =	shiftZ;
			//shelfeMesh.x = shelfSpacing * _scale;
			shelfeMesh.sorting = Sorting.DYNAMIC_BSP;
			addChild(shelfeMesh);
			_shelvesMeshes.push(shelfeMesh);
			
			for (j = 0; j < shelfeMesh.faces.length; j++) {
				sideInfo = shelfeMesh.faces[j].id as SideInfo;
				
				if (sideInfo == null) {
					continue;
				}
				
				sideInfo.type = SideInfo.CORPUS_FACE;
			}
			
		}
		
		private function buildDecor():void {
			var i:int;
			var edgeArr:Array = _model.shapePoints;
			var decorEdge:Array =_model.foots.decorPoints;
			
			if (decorEdge== null || decorEdge.length == 0) {
				// create points
				decorEdge = [];
				 if (edgeArr!= null && 
					_model.shapePointsSide == FurnitureModel.SHAPE_SIDE_TOP &&
					_model.faces != null && _model.faces.length > 0) {	
						var index:int = _model.faces[0].index;
						//copy and shift by Y axis
						var pointsXY:Array;
						var pointsXYClone:Array;
						for (i = index-1; i <= index; i++)
						{
							pointsXY = edgeArr[i];
							pointsXYClone = [];
							var j:int = 0;
							while (j < pointsXY.length) {
								pointsXYClone.push(pointsXY[j]);
								pointsXYClone.push(pointsXY[j+1] - DECOR_FRONT_SPACING );
								j += 2;
							}
							
							decorEdge.push(pointsXYClone);
						}
				 }
			}
			
			if (decorEdge== null) {
				decorEdge = [];
			}
			
			if ( decorEdge.length == 0) {
				decorEdge.push([_model.furnitureWidth, 
											_model.furnitureDepth - DECOR_FRONT_SPACING ]);
				decorEdge.push([0, _model.furnitureDepth - DECOR_FRONT_SPACING]);
			}
			
			// make model
			var decorModel:FurnitureModel = new FurnitureModel();
			decorModel.extra = "";
			decorModel.furnitureHeight = 100 ;
			decorModel.furnitureWidth = _model.furnitureWidth;
			decorModel.furnitureDepth = 1;
			decorModel.shapePointsSide = FurnitureModel.SHAPE_SIDE_TOP;
			log("decor: " + decorEdge);
			decorModel.shapePoints =	decorEdge;
			decorModel.hasTabletop = false;
			decorModel.doubleSided = false;
			decorModel.side = _model.side;
			
			_decorMesh = new FurnitureMesh(decorModel, _scale, false, false, "decor");
			_decorMesh.sorting = Sorting.DYNAMIC_BSP;
			
			// set faces type
			var sideInfo:SideInfo;
			for (i = 0; i < _decorMesh.faces.length; i++) {
				sideInfo = _decorMesh.faces[i].id as SideInfo;
				
				if (sideInfo == null) {
					continue;
				}
				
				sideInfo.type = SideInfo.CORPUS_FACE;
			}
			
			addChild(_decorMesh);
		}
		
		private function makeEdgeSideAlign(edge:Array):Array
		{
			if ( _furnMesh.model.side == FurnitureModel.SIDE_RIGHT)
			{
				return edge;
			}else if ( _furnMesh.model.side != FurnitureModel.SIDE_LEFT)
			{
				return edge;
			}
			
			var maxX:Number = 0;
			var minX:Number = Number.MAX_VALUE;
			var points:Array = [];
			var pointsXY:Array;
			var pointsXYAdjusted:Array;
			var i:int;
			var j:int;
			for (i = 0; i < edge.length; i++ )
			{
				pointsXY = edge[i];
				for (j = 0; j < pointsXY.length; j += 2 )
				{
					maxX = Math.max(maxX, pointsXY[j]);
					minX = Math.min(minX, pointsXY[j]);
				}
			}
			
			var shapeWidth:Number = maxX - minX;
			
			for (i = 0; i < edge.length; i++ )
			{
				pointsXY = edge[i];
				pointsXYAdjusted = [];
				
				for (j = 0; j < pointsXY.length; j += 2 )
				{
					pointsXYAdjusted.push(maxX - pointsXY[j] + minX);
					pointsXYAdjusted.push(pointsXY[j+1]);
				}
				
				points.push(pointsXYAdjusted);
			}
			
			return points;
		}
		
	
		public function setFacadePalette(facadePalette:IPalette, techPalette:IPalette):void {
			if(facadePalette != null){
					_furnMesh.setFacadePalette(facadePalette, techPalette);
				}else {
					_furnMesh.setFacadePalette(new ColorPalette(0xFF8000), techPalette);
				}
		}
		
		public function setTabletopPalette(palette:IPalette):void {
			if (_tabletopMesh != null) {
				if(palette != null){
					_tabletopMesh.setTabletopPalette(palette);
				}else {
					_tabletopMesh.setTabletopPalette(new ColorPalette(0xC0C0C0));
				}
			}
		}
		
		public function setCorpusPalette(palette:IPalette):void {
			if(palette!=null){
				_furnMesh.setCorpusPalette(palette);
				setDecorPalette(palette);
				setShelvesPalette(palette);
			}else {
				var colorPalette:ColorPalette = new ColorPalette(0xC0C0C0);
				_furnMesh.setCorpusPalette(colorPalette);
				setDecorPalette(colorPalette);
				setShelvesPalette(colorPalette);
			}
		}
		
		public function setDecorPalette(palette:IPalette):void {
			if (_decorMesh == null) {
				return;
			}
			_decorMesh.setCorpusPalette(palette);
		}
		
		public function setShelvesPalette(palette:IPalette):void {
			if (_shelvesMeshes == null) {
				return;
			}
			if (palette == null) {
				return;
			}
			
			for (var i:int = 0 ; i < _shelvesMeshes.length; i++ ) {
				_shelvesMeshes[i].setCorpusPalette(palette);
			}
		}
		
		public function get furnitureHeight():Number 
		{
			return _furnMesh.model.furnitureHeight;
		}
		
		public function get furnitureWidth():Number 
		{
			return _furnMesh.model.furnitureWidth;
		}
		
			public function get furnitureDepth():Number 
		{
			return _furnMesh.model.furnitureDepth;
		}
		
		
		public function getSizesTexture():Vector.<String>
		{
			return _furnMesh.model.getSizesNeeded();
		}
		
		private function log(msg:String):void {
			Logger.log(this, msg);
		}
	}

}